package cn.com.guage.transtation;

import com.mysql.cj.util.StringUtils;

import java.sql.*;

// 定义参与者接口
interface Participant {
    String  getDbname();
    boolean canCommit();
    void preCommit();
    void doCommit();
    void doAbort();
}

// 定义协调者类
class Coordinator {
    private Participant[] participants;

    public Coordinator(Participant[] participants) {
        this.participants = participants;
    }

    public boolean transfer(int fromId, int toId, double amount) {
        // 询问阶段
        boolean allCanCommit = true;
        for (Participant participant : participants) {
            String dbName = participant.getDbname();
            Boolean canCommit = participant.canCommit();
            if (!canCommit) {
                allCanCommit = false;
                break;
            }
        }
        if (allCanCommit) {
            // 预提交阶段
            for (Participant participant : participants) {
                participant.preCommit();
            }

            // 提交阶段
            for (Participant participant : participants) {
                participant.doCommit();
            }
            return true;
        } else {
            // 中断阶段
            for (Participant participant : participants) {
                participant.doAbort();
            }
            return false;
        }
    }
}

// 定义银行参与者类 张三
class ZhangsanBankParticipant implements Participant {
    private String dbName;
    private String url;
    private String username;
    private String password;
    private int fromId;
    private int toId;
    private double amount;
    private Connection connection;

    public ZhangsanBankParticipant(String dbName,String url, String username, String password, int fromId, int toId, double amount) {
        this.dbName = dbName;
        this.url = url;
        this.username = username;
        this.password = password;
        this.fromId = fromId;
        this.toId = toId;
        this.amount = amount;
    }


    @Override
    public String getDbname() {
        return this.dbName;
    }

    @Override
    public boolean canCommit() {
        try {
            connection = DriverManager.getConnection(url, username, password);
            connection.setAutoCommit(false);
            String selectSql = "SELECT balance FROM account WHERE id = ?";
            try (PreparedStatement pstmt = connection.prepareStatement(selectSql)) {
                pstmt.setInt(1, fromId);
                try (ResultSet rs = pstmt.executeQuery()) {
                    if (rs.next()) {
                        double balance = rs.getDouble("balance");
                        return balance > amount;
                    }
                }
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public void preCommit() {
        try {
            connection = DriverManager.getConnection(url, username, password);
            connection.setAutoCommit(false);
            String updateFromSql = "UPDATE account SET balance = balance - ? WHERE id = ?";
            try (PreparedStatement pstmt = connection.prepareStatement(updateFromSql)) {
                pstmt.setDouble(1, amount);
                pstmt.setInt(2, fromId);
                pstmt.executeUpdate();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void doCommit() {
        try {
            connection.commit();
            connection.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void doAbort() {
        try {
            connection.rollback();
            connection.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}


// 定义银行参与者类 张三
class LisiBankParticipant implements Participant {
    private String dbName;
    private String url;
    private String username;
    private String password;
    private int fromId;
    private int toId;
    private double amount;
    private Connection connection;

    public LisiBankParticipant(String dbName,String url, String username, String password, int fromId, int toId, double amount) {
        this.dbName = dbName;
        this.url = url;
        this.username = username;
        this.password = password;
        this.fromId = fromId;
        this.toId = toId;
        this.amount = amount;
    }


    @Override
    public String getDbname() {
        return this.dbName;
    }

    @Override
    public boolean canCommit() {
        try {
            connection = DriverManager.getConnection(url, username, password);
            connection.setAutoCommit(false);
            String selectSql = "SELECT name FROM account WHERE  name='李四'";
            try (PreparedStatement pstmt = connection.prepareStatement(selectSql)) {
                try (ResultSet rs = pstmt.executeQuery()) {
                    if (rs.next()) {
                        String name = rs.getString("name");
                        if (!StringUtils.isNullOrEmpty(name)) {
                            return true;
                        }
                        return false;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public void preCommit() {
        try {
            connection = DriverManager.getConnection(url, username, password);
            connection.setAutoCommit(false);
            String updateToSql = "UPDATE account SET balance = balance + ? WHERE id = ?";
            try (PreparedStatement pstmt = connection.prepareStatement(updateToSql)) {
                pstmt.setDouble(1, amount);
                pstmt.setInt(2, toId);
                pstmt.executeUpdate();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void doCommit() {
        try {
            connection.commit();
            connection.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void doAbort() {
        try {
            connection.rollback();
            connection.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

// 主类
public class ThreePhaseCommitTransfer {
    public static void main(String[] args) {
        String url1 = "jdbc:mysql://localhost:3306/3pc-db1";
        String url2 = "jdbc:mysql://localhost:3306/3pc-db2";
        String username = "root";
        String password = "123456";
        int zhangsanId = 1;
        int lisiId = 2;
        double amount = 1000.0;

        Participant participant1 = new ZhangsanBankParticipant("db1",url1, username, password, zhangsanId, lisiId, amount);
        Participant participant2 = new LisiBankParticipant("db2",url2, username, password, zhangsanId, lisiId, amount);
        Participant[] participants = {participant1, participant2};

        Coordinator coordinator = new Coordinator(participants);
        boolean result = coordinator.transfer(zhangsanId, lisiId, amount);

        if (result) {
            System.out.println("转账成功");
        } else {
            System.out.println("转账失败");
        }
    }
}    